package com.lzw.breezeNovel.webApp.service.impl.video;

import com.lzw.breezeNovel.common.exception.BaseException;
import com.lzw.breezeNovel.common.result.ResultCodeEnum;
import com.lzw.breezeNovel.model.entity.pojo.video.Anime;
import com.lzw.breezeNovel.model.entity.pojo.video.Movie;
import com.lzw.breezeNovel.model.entity.pojo.video.TvSeries;
import com.lzw.breezeNovel.model.entity.query.Search;
import com.lzw.breezeNovel.webApp.mapper.video.AnimeMapper;
import com.lzw.breezeNovel.webApp.mapper.video.MovieMapper;
import com.lzw.breezeNovel.webApp.mapper.video.TvSeriesMapper;
import com.lzw.breezeNovel.webApp.queue.MergedItem;
import com.lzw.breezeNovel.webApp.service.video.SearchService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 清风明月
 * @Package com.lzw.breezeNovel.webApp.service.impl.video
 * @date 2025/3/18
 * @description 搜索
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class SearchServiceImpl implements SearchService {

    /**
     * 注入动漫的mapper
     */
    @Autowired
    private AnimeMapper animeMapper;

    /**
     * 注入电影的mapper
     */
    @Autowired
    private MovieMapper movieMapper;
    /**
     * 注入电视剧的mapper
     */
    @Autowired
    private TvSeriesMapper tvSeriesMapper;
    /**
     * 注入自定义线程池
     */
    @Autowired
    private ThreadPoolExecutor executor;


    /**
     * 搜索数据
     * @param search
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List search(@NotNull Search search) {
        //计算分页
        int startPage = startPage(search.getPageNum(), search.getPageSize());
        //定义三个集合
        List<Movie> movieList = null;
        List<TvSeries> tvSeriesList = null;

        try {
            //开启一个异步任务，去动漫里面搜索
            CompletableFuture<List<Anime>> anime = CompletableFuture.supplyAsync(()->{
                return  animeMapper.search(search);
            },executor);
            //开启一个异步任务，去电影里面搜索
            CompletableFuture<List<Movie>> movie = CompletableFuture.supplyAsync(()->{
                return movieMapper.search(search);
            },executor);
            // 开启一个异步任务，去电视剧里面搜索
            CompletableFuture<List<TvSeries>> tv = CompletableFuture.supplyAsync(()->{
                return tvSeriesMapper.search(search);
            },executor);
            //等待三个异步任务完成
            CompletableFuture.allOf(anime,movie,tv).join();
            //获取三个异步任务的结果
            List<Anime> animeList = anime.get();
            movieList = movie.get();
            tvSeriesList = tv.get();
            // 3. 高效合并三个有序列表
            return mergeSortedLists(animeList, movieList, tvSeriesList, 15);
        } catch (InterruptedException | ExecutionException e) {
           log.error("搜索失败",e);
            Thread.currentThread().interrupt();
            throw new BaseException(ResultCodeEnum.SERVICE_ERROR);
        }
    }

    /**
     * 高效合并三个有序列表
     * @param animeList 动画列表
     * @param movieList 电影列表
     * @param tvSeriesList 电视剧列表
     * @param limit 最大合并数量
     * @return 合并后的列表，可能包含动画、电影或电视剧对象
     */
    @Nullable
    @Contract(pure = true)
    private List mergeSortedLists(List<Anime> animeList, List<Movie> movieList, List<TvSeries> tvSeriesList, int limit) {
        // 使用自定义的优先队列元素，优先队列会根据MergedItem中的value值进行排序
        PriorityQueue<MergedItem> heap = new PriorityQueue<>();

        // 初始化堆，添加各列表的首个元素到堆中
        addListToHeap(animeList, heap);
        addListToHeap(movieList, heap);
        addListToHeap(tvSeriesList, heap);

        // 创建结果列表，初始容量为limit
        List<Object> result = new ArrayList<>(limit);
        // 当结果列表未达到限制数量且堆不为空时，循环获取最小值
        while (result.size() < limit && !heap.isEmpty()) {
            // 获取并移除堆中最小值对应的MergedItem
            MergedItem item = heap.poll();
            // 将获取到的元素添加到结果列表
            result.add(item.getItem());

            // 如果当前元素所属的列表还有下一个元素，则将其添加到堆中
            if (item.getIterator().hasNext()) {
                Object next = item.getIterator().next();
                heap.add(new MergedItem(next, item.getIterator()));
            }
        }
        // 返回合并后的结果列表
        return result;
    }

    /**
     * 将列表转换为迭代器并添加到堆中
     * @param list 需要添加的列表
     * @param heap 优先队列
     */
    private void addListToHeap(List<?> list, PriorityQueue<MergedItem> heap) {
        // 如果列表不为空且不为空列表
        if (list != null && !list.isEmpty()) {
            // 获取列表的迭代器
            Iterator<?> iterator = list.iterator();
            // 获取列表的第一个元素
            Object first = iterator.next();
            // 将第一个元素和迭代器封装成MergedItem并添加到堆中
            heap.add(new MergedItem(first, iterator));
        }
    }


    /**
     * 计算分页
     * @param pageNo
     * @param size
     * @return
     */
    public int startPage(Integer pageNo, Integer size){
        //判断分页数据是否为空
        pageNo = Optional.of(pageNo).orElse(1);
        size = Optional.of(size).orElse(10);
        pageNo = Math.max(pageNo, 1);
        size = Math.max(size, 1);
        //计算分页
        pageNo = (pageNo - 1) * size;
        return pageNo;
    }
}
